﻿using Caliburn.Micro;
using Microsoft.Win32;
using SD.Common;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.Infrastructure.WPF.Extensions;
using SD.Infrastructure.WPF.Interfaces;
using SD.Infrastructure.WPF.Models;
using SD.IOC.Core.Mediators;
using SD.Toolkits.Excel;
using SlamDunk.MES.Client.ViewModels.Facility;
using SlamDunk.MES.IAppService.DTOs.Outputs.FoundationContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.StockContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.MES.Presentation;
using SlamDunk.MES.Presentation.Maps;
using SlamDunk.MES.Presentation.Models.ExportModels;
using SlamDunk.MES.Presentation.Models.NotifyModels;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace SlamDunk.MES.Client.ViewModels.BoundRecord
{
    /// <summary>
    /// 库存流水首页视图模型
    /// </summary>
    public class IndexViewModel : ScreenBase, IPaginatable
    {
        #region # 字段及构造器

        /// <summary>
        /// 资源定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IResourceContract> _resourceContract;

        /// <summary>
        /// 基础定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IFoundationContract> _foundationContract;

        /// <summary>
        /// 库存管理服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IStockManageContract> _stockManageContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public IndexViewModel(ServiceProxy<IResourceContract> resourceContract, ServiceProxy<IFoundationContract> foundationContract, ServiceProxy<IStockManageContract> stockManageContract, IWindowManager windowManager)
        {
            this._resourceContract = resourceContract;
            this._foundationContract = foundationContract;
            this._stockManageContract = stockManageContract;
            this._windowManager = windowManager;

            //默认值
            this.PageIndex = 1;
            this.PageSize = 20;
        }

        #endregion

        #region # 属性

        #region 页码 —— int PageIndex
        /// <summary>
        /// 页码
        /// </summary>
        [DependencyProperty]
        public int PageIndex { get; set; }
        #endregion

        #region 页容量 —— int PageSize
        /// <summary>
        /// 页容量
        /// </summary>
        [DependencyProperty]
        public int PageSize { get; set; }
        #endregion

        #region 总记录数 —— int RowCount
        /// <summary>
        /// 总记录数
        /// </summary>
        [DependencyProperty]
        public int RowCount { get; set; }
        #endregion

        #region 总页数 —— int PageCount
        /// <summary>
        /// 总页数
        /// </summary>
        [DependencyProperty]
        public int PageCount { get; set; }
        #endregion

        #region 出/入库类型字典 —— IDictionary<string, string> StockDirectionTypes
        /// <summary>
        /// 出/入库类型字典
        /// </summary>
        [DependencyProperty]
        public IDictionary<string, string> StockDirectionTypes { get; set; }
        #endregion

        #region 储存位置类型字典 —— IDictionary<string, string> StorageLocationTypes
        /// <summary>
        /// 储存位置类型字典
        /// </summary>
        [DependencyProperty]
        public IDictionary<string, string> StorageLocationTypes { get; set; }
        #endregion

        #region 储存位置列表 —— ObservableCollection<IdentiferNameNm> StorageLocations
        /// <summary>
        /// 储存位置列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<IdentiferNameNm> StorageLocations { get; set; }
        #endregion

        #region 已选出/入库类型 —— StockDirectionType? SelectedStockDirectionType
        /// <summary>
        /// 已选出/入库类型
        /// </summary>
        [DependencyProperty]
        public StockDirectionType? SelectedStockDirectionType { get; set; }
        #endregion

        #region 已选储存位置类型 —— StorageLocationType? SelectedStorageLocationType
        /// <summary>
        /// 已选储存位置类型
        /// </summary>
        [DependencyProperty]
        public StorageLocationType? SelectedStorageLocationType { get; set; }
        #endregion

        #region 已选储存位置 —— IdentiferNameNm SelectedStorageLocation
        /// <summary>
        /// 已选储存位置
        /// </summary>
        [DependencyProperty]
        public IdentiferNameNm SelectedStorageLocation { get; set; }
        #endregion

        #region 已选工厂模型 —— Node SelectedFacility
        /// <summary>
        /// 已选工厂模型
        /// </summary>
        [DependencyProperty]
        public Node SelectedFacility { get; set; }
        #endregion

        #region 出/入库记录列表 —— ObservableCollection<Wrap<BoundRecordInfo>> BoundRecords
        /// <summary>
        /// 出/入库记录列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<Wrap<BoundRecordInfo>> BoundRecords { get; set; }
        #endregion

        #region 储存位置列表可见性 —— Visibility StorageLocationComboBoxVisibility
        /// <summary>
        /// 储存位置列表可见性
        /// </summary>
        [DependencyProperty]
        public Visibility StorageLocationComboBoxVisibility { get; set; }
        #endregion

        #region 储存位置文本可见性 —— Visibility StorageLocationTextBoxVisibility
        /// <summary>
        /// 储存位置文本可见性
        /// </summary>
        [DependencyProperty]
        public Visibility StorageLocationTextBoxVisibility { get; set; }
        #endregion

        #region 储存位置文本 —— string StorageLocationText
        /// <summary>
        /// 储存位置文本
        /// </summary>
        [DependencyProperty]
        public string StorageLocationText { get; set; }
        #endregion

        #endregion

        #region # 方法

        //Initializations

        #region 初始化 —— override async Task OnInitializeAsync(CancellationToken cancellationToken)
        /// <summary>
        /// 初始化
        /// </summary>
        protected override async Task OnInitializeAsync(CancellationToken cancellationToken)
        {
            this.StockDirectionTypes = typeof(StockDirectionType).GetEnumMembers();
            this.StorageLocationTypes = typeof(StorageLocationType).GetEnumMembers();
            this.StorageLocationComboBoxVisibility = Visibility.Visible;
            this.StorageLocationTextBoxVisibility = Visibility.Collapsed;

            await this.ReloadBoundRecords();
        }
        #endregion


        //Actions

        #region 选择工厂模型 —— async void SelectFacility()
        /// <summary>
        /// 选择工厂模型
        /// </summary>
        public async void SelectFacility()
        {
            this.Busy();

            SelectFacilityViewModel viewModel = ResolveMediator.Resolve<SelectFacilityViewModel>();
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                this.SelectedFacility = viewModel.SelectedFacility;
            }

            this.Idle();
        }
        #endregion

        #region 清空工厂模型 —— void ClearFacility()
        /// <summary>
        /// 清空工厂模型
        /// </summary>
        public void ClearFacility()
        {
            this.SelectedFacility = null;
        }
        #endregion

        #region 加载储存位置列表 —— async void LoadStorageLocations()
        /// <summary>
        /// 加载储存位置列表
        /// </summary>
        public async void LoadStorageLocations()
        {
            this.Busy();

            await this.ReloadStorageLocations();

            this.Idle();
        }
        #endregion

        #region 加载出/入库记录列表 —— async void LoadBoundRecords()
        /// <summary>
        /// 加载出/入库记录列表
        /// </summary>
        public async void LoadBoundRecords()
        {
            await this.ReloadBoundRecords();
        }
        #endregion

        #region 导出出/入库记录列表 —— async void ExportBoundRecords()
        /// <summary>
        /// 导出出/入库记录列表
        /// </summary>
        public async void ExportBoundRecords()
        {
            this.Busy();

            string storageLocationId = this.SelectedStorageLocationType == StorageLocationType.Description
                ? this.StorageLocationText
                : this.SelectedStorageLocation?.Id.ToString();
            PageModel<BoundRecordInfo> pageModel = await Task.Run(() => this._stockManageContract.Channel.GetBoundRecordsByPage(null,
               null, this.SelectedStockDirectionType, this.SelectedStorageLocationType, storageLocationId, null, null, this.SelectedFacility?.Id, 1, int.MaxValue));

            BoundRecordEm[] boundRecordEms = pageModel.Datas.Select(x => x.ToExportView()).ToArray();

            #region # 验证

            if (!boundRecordEms.Any())
            {
                MessageBox.Show("导出数据为空，不能进行导出！", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            #endregion

            SaveFileDialog saveFileDialog = new SaveFileDialog
            {
                Filter = Constants.ExeclFileExtensionsFilter,
                FileName = $"出入库流水_{DateTime.Now.ToString(Constants.ExportFileTimeFormat)}",
                AddExtension = true,
                RestoreDirectory = true
            };
            if (saveFileDialog.ShowDialog() == true)
            {
                string filePath = saveFileDialog.FileName;
                ExcelWriter.WriteFile(boundRecordEms, filePath);
            }

            this.Idle();
        }
        #endregion


        //Private

        #region 加载储存位置列表 —— async Task ReloadStorageLocations()
        /// <summary>
        /// 加载储存位置列表
        /// </summary>
        private async Task ReloadStorageLocations()
        {
            #region # 验证

            if (this.SelectedStorageLocationType == null)
            {
                this.StorageLocations = new ObservableCollection<IdentiferNameNm>();
                return;
            }

            #endregion

            if (this.SelectedStorageLocationType == StorageLocationType.Description)
            {
                this.StorageLocationComboBoxVisibility = Visibility.Collapsed;
                this.StorageLocationTextBoxVisibility = Visibility.Visible;
                this.StorageLocations = new ObservableCollection<IdentiferNameNm>();
            }
            else
            {
                this.StorageLocationComboBoxVisibility = Visibility.Visible;
                this.StorageLocationTextBoxVisibility = Visibility.Collapsed;
                IEnumerable<IdentiferNameNm> identiferNames = Array.Empty<IdentiferNameNm>();
                switch (this.SelectedStorageLocationType)
                {
                    case StorageLocationType.ProductionDomain:
                        IEnumerable<FacilityInfo> facilities = await Task.Run(() => this._foundationContract.Channel.GetFacilities(null, null, FacilityType.ProductionDomain, null));
                        identiferNames = facilities.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.BusinessDomain:
                        facilities = await Task.Run(() => this._foundationContract.Channel.GetFacilities(null, null, FacilityType.BusinessDomain, null));
                        identiferNames = facilities.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.StorageDomain:
                        facilities = await Task.Run(() => this._foundationContract.Channel.GetFacilities(null, null, FacilityType.StorageDomain, null));
                        identiferNames = facilities.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.Person:
                        PageModel<PersonInfo> persons = await Task.Run(() => this._resourceContract.Channel.GetPersonsByPage(null, this.SelectedFacility?.Id, null, 1, int.MaxValue));
                        identiferNames = persons.Datas.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.Team:
                        PageModel<TeamInfo> teams = await Task.Run(() => this._resourceContract.Channel.GetTeamsByPage(null, this.SelectedFacility?.Id, 1, int.MaxValue));
                        identiferNames = teams.Datas.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.Customer:
                        PageModel<EnterpriseInfo> enterprises = await Task.Run(() => this._resourceContract.Channel.GetEnterprisesByPage(null, EnterpriseType.Customer, this.SelectedFacility?.Id, 1, int.MaxValue));
                        identiferNames = enterprises.Datas.Select(x => x.ToIdentiferName());
                        break;
                    case StorageLocationType.Supplier:
                        enterprises = await Task.Run(() => this._resourceContract.Channel.GetEnterprisesByPage(null, EnterpriseType.Supplier, this.SelectedFacility?.Id, 1, int.MaxValue));
                        identiferNames = enterprises.Datas.Select(x => x.ToIdentiferName());
                        break;
                }
                this.StorageLocations = new ObservableCollection<IdentiferNameNm>(identiferNames);
            }
        }
        #endregion

        #region 加载出/入库记录列表 —— async Task ReloadBoundRecords()
        /// <summary>
        /// 加载出/入库记录列表
        /// </summary>
        private async Task ReloadBoundRecords()
        {
            this.Busy();

            string storageLocationId = this.SelectedStorageLocationType == StorageLocationType.Description
                ? this.StorageLocationText
                : this.SelectedStorageLocation?.Id.ToString();
            PageModel<BoundRecordInfo> pageModel = await Task.Run(() => this._stockManageContract.Channel.GetBoundRecordsByPage(null, null, this.SelectedStockDirectionType, this.SelectedStorageLocationType, storageLocationId, null, null, this.SelectedFacility?.Id, this.PageIndex, this.PageSize));
            this.RowCount = pageModel.RowCount;
            this.PageCount = pageModel.PageCount;
            this.BoundRecords = new ObservableCollection<Wrap<BoundRecordInfo>>(pageModel.Datas.Select(x => x.Wrap()));

            this.Idle();
        }
        #endregion

        #endregion
    }
}
